home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / interapplication comm / 7edit / source / svaeaccessors.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  30.0 KB  |  1,020 lines

  1. /*
  2.     File:        SVAEAccessors.c
  3.  
  4.     Contains:    
  5.  
  6.     Written by: Original version by Jon Lansdell and Nigel Humphreys.
  7.                 3.1 updates by Greg Sutton.
  8.  
  9.     Copyright:    Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved.
  10.  
  11.                 You may incorporate this Apple sample source code into your program(s) without
  12.                 restriction. This Apple sample source code has been provided "AS IS" and the
  13.                 responsibility for its operation is yours. You are not permitted to redistribute
  14.                 this Apple sample source code as "Apple sample source code" after having made
  15.                 changes. If you're going to re-distribute the source, we require that you make
  16.                 it clear in the source that the code was descended from Apple sample source
  17.                 code, but that you've made changes.
  18.  
  19.     Change History (most recent first):
  20.                 7/20/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  21.                 
  22.  
  23. */
  24.  
  25. #include "SVAEAccessors.h"
  26.  
  27. #include <Menus.h>
  28. #include <PLStringFuncs.h>
  29. #include <Scrap.h>
  30. #include <TextEdit.h>
  31. #include <AEObjects.h>
  32. #include <AEPackObject.h>
  33. #include <AERegistry.h>
  34. #include "SVEditGlobals.h"
  35. #include "SVEditUtils.h"
  36. #include "SVEditAEUtils.h"
  37. #include "SVEditWindow.h"
  38. #include "SVEditFile.h"
  39. #include "SVAppleEvents.h"
  40.  
  41. #include "SVToken.h"
  42. #include "SVAETextUtils.h"
  43. #include "SVAEWindowUtils.h"
  44.  
  45.  
  46. #pragma segment AppleEvent
  47.  
  48. // Install accessors that are used when AEResolve is called to convert
  49. // object specifiers into internal representations (tokens).
  50.  
  51. OSErr    InstallAccessors(void)
  52. {
  53.     OSErr    err;
  54.  
  55.     err = AEInstallObjectAccessor(cApplication, typeNull,            NewOSLAccessorProc(ApplicationFromNullAccessor), 0, false);
  56.     err = AEInstallObjectAccessor(cWindow,      typeNull,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  57.     err = AEInstallObjectAccessor(cDocument,    typeNull,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  58.     err = AEInstallObjectAccessor(cProperty,    typeNull,             NewOSLAccessorProc(PropertyFromNullAccessor), 0, false);
  59.  
  60.     err = AEInstallObjectAccessor(cWindow,      typeMyAppl,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  61.     err = AEInstallObjectAccessor(cDocument,    typeMyAppl,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  62.     err = AEInstallObjectAccessor(cProperty,    typeMyAppl,         NewOSLAccessorProc(PropertyFromApplAccessor), 0, false);
  63.  
  64.             // Handle text from a window
  65.             // e.g. some character of last window
  66.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyWndw,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  67.     err = AEInstallObjectAccessor(cChar,        typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  68.     err = AEInstallObjectAccessor(cText,         typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  69.     err = AEInstallObjectAccessor(cWord,        typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  70.     err = AEInstallObjectAccessor(cParagraph,    typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  71.     err = AEInstallObjectAccessor(cProperty,    typeMyWndw,            NewOSLAccessorProc(PropertyFromWndwAccessor), 0, false);
  72.  
  73.             // Handle text items within text items
  74.             // e.g. last word of first paragraph of front window
  75.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyText,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  76.     err = AEInstallObjectAccessor(cChar,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  77.     err = AEInstallObjectAccessor(cText,         typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  78.     err = AEInstallObjectAccessor(cWord,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  79.     err = AEInstallObjectAccessor(cParagraph,    typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  80.     err = AEInstallObjectAccessor(cProperty,    typeMyText,            NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  81.  
  82.             // Handle text items from lists (of hopefully text items) also
  83.             // e.g. every word of every paragraph of front window
  84.             // or even - every word of every character of every paragraph of front window
  85.     err = AEInstallObjectAccessor(cInsertionPoint,typeAEList,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  86.     err = AEInstallObjectAccessor(cChar,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  87.     err = AEInstallObjectAccessor(cText,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  88.     err = AEInstallObjectAccessor(cWord,        typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  89.     err = AEInstallObjectAccessor(cParagraph,    typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  90.     err = AEInstallObjectAccessor(cProperty,    typeAEList,         NewOSLAccessorProc(PropertyFromListAccessor), 0, false);
  91.  
  92.             // This is for 'select insertion point before contents of document 1'
  93.     err = AEInstallObjectAccessor(cInsertionPoint,     typeMyWindowProp,    NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  94.  
  95.             // This accessor is for getting properties of window properties
  96.             // e.g. font of contents of window 1
  97.             // Relies on ability to coerce from a window property to text
  98.             // for certain properties.
  99.     err = AEInstallObjectAccessor(cProperty,         typeMyWindowProp,    NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  100.  
  101.     return(err);
  102. }
  103.  
  104.  
  105. // Given selectionData of formAbsolutePosition for a window this routine returns
  106. // a WindowToken descriptor for specified window.
  107. //
  108. // e.g.    tell application '7Edit'
  109. //            window 1
  110. //            --first document
  111. //            --some window
  112. //            --every window
  113. //        end tell
  114.  
  115. OSErr    WindowFormAbsolutePosition(const AEDesc    *selectionData, AEDesc* result)
  116. {
  117.     AEDesc    itemDesc = {typeNull, NULL};
  118.     short    windowCount,
  119.             index;
  120.     OSErr    err;
  121.  
  122.     windowCount = CountWindows();
  123.     
  124.     if (! windowCount)
  125.         return(errAEIllegalIndex);
  126.     
  127.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  128.     {
  129.         switch (*(DescType *)*selectionData->dataHandle)
  130.         {
  131.             case kAEFirst:
  132.                 index = 1;
  133.                 break;
  134.     
  135.             case kAELast:
  136.                 index = windowCount;
  137.                 break;
  138.     
  139.             case kAEMiddle:
  140.                 index = (windowCount + 1) / 2;
  141.                 break;
  142.     
  143.             case kAEAny:
  144.                 index = (Random() % windowCount) + 1;
  145.                 break;
  146.     
  147.             case kAEAll:
  148.                 err = AECreateList(NULL, 0 , false, result);
  149.                 if (noErr != err) goto done;
  150.                 
  151.                 for (index = 1; index <= windowCount; index++)
  152.                 {
  153.                     err = GetDescOfNthWindow(index, &itemDesc);
  154.                     if (noErr != err) goto done;
  155.                     
  156.                     err = AEPutDesc(result, 0, &itemDesc);
  157.                     if (noErr != err) goto done;
  158.                     
  159.                     if (itemDesc.dataHandle)
  160.                         AEDisposeDesc(&itemDesc);
  161.                 }
  162.                 
  163.                 goto done;        // We have created our list descriptor
  164.                 break;            // so we can just tidy up and return.
  165.                 
  166.             default:
  167.                 err = errAETypeError;
  168.         }
  169.     }
  170.     else
  171.         err = GetIntegerFromDescriptor(selectionData, &index);
  172.  
  173.     if (noErr != err) goto done;
  174.     
  175.     if (index < 0)        // Handle negative indexes
  176.         index = windowCount + index + 1;
  177.         
  178.     if (index > windowCount || index <= 0)
  179.         err = errAEIllegalIndex;
  180.     else
  181.         err = GetDescOfNthWindow(index, result);
  182.  
  183. done:    
  184.     if (itemDesc.dataHandle)
  185.         AEDisposeDesc(&itemDesc);
  186.  
  187.     return(err);
  188. } // WindowFormAbsolutePosition
  189.  
  190.  
  191. // Given a formName descriptor in selectionData, this routine returns a
  192. // WindowToken descriptor for the window with that name.
  193. //
  194. // e.g.    tell application '7Edit'
  195. //            document "Untitled"
  196. //        end tell
  197.  
  198. OSErr    WindowFormName(const AEDesc    *selectionData, AEDesc* result)
  199. {
  200.     Str255        name;
  201.     OSErr        err;
  202.     
  203.                 // This tries to coerce it first
  204.     err = GetPStringFromDescriptor(selectionData, name);
  205.     if (noErr != err) goto done;
  206.  
  207.     err = GetDescOfNamedWindow(name, result);
  208.  
  209. done:
  210.     return(err);
  211. }
  212.  
  213.  
  214. // Get a WindowToken descriptor for a window or document object specifier
  215. // from NULL (or the application). Only handles formAbsolutePosition and formName
  216. //
  217. // e.g.    tell application '7Edit'
  218. //            window 1
  219. //            --first document
  220. //            --document "Untitled"
  221. //            --every window
  222. //        end tell
  223.  
  224. pascal OSErr    WindowFromNullAccessor(DescType            wantClass,
  225.                                         const AEDesc    *container,
  226.                                         DescType          containerClass,
  227.                                         DescType        form, 
  228.                                         const AEDesc    *selectionData,
  229.                                         AEDesc            *value,
  230.                                         long            theRefCon)
  231. {
  232. #pragma unused (container,theRefCon)
  233.  
  234.     OSErr       err;
  235.     
  236.         // Can only handle cWindow and cDocument
  237.     if (wantClass != cWindow && wantClass != cDocument)
  238.         return(errAEWrongDataType);
  239.         
  240.         // Can only handle typeNull and typeMyAppl
  241.     if (containerClass != typeNull && containerClass != typeMyAppl)
  242.         return(errAENoSuchObject);
  243.     
  244.     switch (form)
  245.     {
  246.         case formAbsolutePosition:
  247.             err = WindowFormAbsolutePosition(selectionData, value);
  248.             break;
  249.             
  250.         case formName:
  251.             err = WindowFormName(selectionData, value);
  252.             break;
  253.             
  254.         default:
  255.             err = errAEBadTestKey;
  256.     }
  257.             
  258.     return(err);
  259. } // WindowFromNullAccessor
  260.  
  261.  
  262. pascal OSErr   ApplicationFromNullAccessor(DescType        wantClass,
  263.                                             const AEDesc    *container,
  264.                                             DescType        containerClass,
  265.                                             DescType        form, 
  266.                                             const AEDesc    *selectionData,
  267.                                             AEDesc            *value,
  268.                                             long            theRefCon)
  269. {
  270. #pragma unused(container,selectionData,theRefCon)
  271.  
  272.     OSErr    myErr;
  273.     AppToken theApp;
  274.     AEDesc   resultDesc;
  275.     
  276.     value->dataHandle     = nil;
  277.     resultDesc.dataHandle = nil;
  278.     
  279.     /* 
  280.         should only be called with wantClass = cWindow and
  281.         with containerClass = typeNull.
  282.         Currently accept as either formName or formAbsolutePosition
  283.     */
  284.     
  285.     if ((wantClass != cApplication) || (containerClass != typeNull) ||
  286.           !((form == formName) || (form == formAbsolutePosition)))
  287.         return(errAEWrongDataType);
  288.     
  289.     if ((form == formName) || (form == formAbsolutePosition))
  290.     {
  291.         theApp.highLongOfPSN = 0;
  292.         theApp.lowLongOfPSN  = kCurrentProcess;
  293.     }
  294.         
  295.     myErr = AECreateDesc(typeMyAppl, (Ptr)&theApp, sizeof(theApp), value);
  296.             
  297.     return(myErr);
  298. }    /* ApplicationFromNullAccessor */
  299.  
  300.  
  301. // Given a formAbsolutePosition selectionData descriptor and a TextToken from
  302. // which to index from. This routine returns a TextToken descriptor for the
  303. // text specified.
  304. //
  305. // e.g.    tell application '7Edit'
  306. //            first word of window 1    -- window one will be dealt with in
  307. //                                    -- WindowFromNullAccessor().
  308. //            --some character of middle paragraph of last document
  309. //                                    -- container token will be a paragraph
  310. //        end tell
  311.  
  312. OSErr    TextFormAbsolutePosition(TextToken* containerToken, AEDesc* selectionData,
  313.                                                     DescType wantClass, AEDesc* result)
  314. {
  315.     DPtr        docPtr;
  316.     short        elementCount;
  317.     AEDesc        aDesc = {typeNull, NULL};
  318.     long        index;
  319.     OSErr        err;
  320.     
  321.     docPtr = DPtrFromWindowPtr(containerToken->tokenWindow);
  322.  
  323.     if (! docPtr)
  324.     {
  325.         err = errAENoSuchObject;
  326.         goto done;
  327.     }
  328.  
  329.     err = CountTextElements(docPtr->theText, containerToken->tokenOffset,
  330.                                 containerToken->tokenLength, wantClass, &elementCount);
  331.     if (noErr != err) goto done;
  332.  
  333.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  334.     {
  335.         switch (*(DescType *)*selectionData->dataHandle)
  336.         {
  337.             case kAEFirst:
  338.                 index = 1;
  339.                 break;
  340.     
  341.             case kAELast:
  342.                 index = elementCount;
  343.                 break;
  344.     
  345.             case kAEMiddle:
  346.                 index = (elementCount + 1) / 2;
  347.                 break;
  348.     
  349.             case kAEAny:
  350.                 index = (Random() % elementCount) + 1;
  351.                 break;
  352.     
  353.             case kAEAll:
  354.                 err = AECreateList(NULL, 0 , false, result);
  355.                 
  356.                 for (index = 1; index <= elementCount; index++)
  357.                 {
  358.                     if (noErr == (err = GetDescOfNthTextElement(index, wantClass,
  359.                                                                 containerToken, &aDesc)))
  360.                     {
  361.                         err = AEPutDesc(result, 0, &aDesc);
  362.                         AEDisposeDesc(&aDesc);
  363.                     }
  364.                 }
  365.                 goto done;        // Created our result - clean up and return
  366.                 break;
  367.     
  368.             default:
  369.                 err = errAETypeError;
  370.         }
  371.     }
  372.     else        // Try and get an index out of the descriptor
  373.         err = GetLongIntFromDescriptor(selectionData, &index);
  374.     
  375.     if (noErr != err) goto done;
  376.                     // kAEAll has already created it's list
  377.     err = GetDescOfNthTextElement(index, wantClass,            // Checks for negatives and
  378.                                 containerToken, result);    // out of range.
  379.                                         
  380. done:
  381.     if (aDesc.dataHandle)
  382.         AEDisposeDesc(&aDesc);
  383.  
  384.     return(err);
  385. }
  386.  
  387.  
  388. // Given a TextToken container and a formRange descriptor. This routine
  389. // creates a TextToken descriptor starting at the the beginning of the
  390. // first item in the range and ending at the end of the last item in the range.
  391. //
  392. // e.g.    tell application '7Edit'
  393. //            paragraphs 2 thru 3 of document 1
  394. //        end tell
  395.  
  396. OSErr    TextFormRange(TextToken* containerToken, AEDesc* selectionData,
  397.                                                     DescType wantClass, AEDesc* result)
  398. {
  399. #pragma unused(wantClass)
  400.  
  401.     AEDesc        selectionRecord = {typeNull, NULL};
  402.     TextToken    startToken,
  403.                 stopToken;
  404.     DescType    returnedType;
  405.     Size        actualSize;
  406.     OSErr        err;
  407.  
  408.         // coerce the selection data into an AERecord
  409.     err = AECoerceDesc(selectionData, typeAERecord, &selectionRecord);
  410.     if (noErr != err) goto done;
  411.     
  412.         // get the start object as a text token this will reenter
  413.         // TextElemFromTextAccessor() but as formAbsolutePosition via 
  414.         // our installed coercion handler CoerceObjToAnything()
  415.         // because the keyAERangeStart parameter is actually an object specifier.
  416.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStart, typeMyText,
  417.                             &returnedType, (Ptr)&startToken, sizeof(startToken), &actualSize);
  418.     if (noErr != err) goto done;
  419.     
  420.         // now do the same for the stop object
  421.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStop, typeMyText,
  422.                             &returnedType, (Ptr)&stopToken, sizeof(stopToken), &actualSize);
  423.     if (noErr != err) goto done;
  424.     
  425.     if (containerToken->tokenWindow != startToken.tokenWindow
  426.             || containerToken->tokenWindow != stopToken.tokenWindow)
  427.     {
  428.         err = errAECorruptData;        // or whatever
  429.         goto done;
  430.     }
  431.         
  432.         // Use startToken to create result descriptor
  433.     startToken.tokenLength = stopToken.tokenOffset + stopToken.tokenLength - startToken.tokenOffset;
  434.                                                          
  435.     err = AECreateDesc(typeMyText, (Ptr)&startToken, sizeof(startToken), result);
  436.  
  437. done:
  438.     if (selectionRecord.dataHandle)
  439.         AEDisposeDesc(&selectionRecord);
  440.  
  441.     return(err);
  442. }
  443.  
  444.  
  445. // Given a container TextToken and a formRelativePosition selectionData descriptor
  446. // this routine returns a TextToken descriptor to the reative wantClass object
  447. // specified.
  448. // This routine currently only handles relative positions for a wantClass
  449. // of cInsertionPoint.
  450. //
  451. // e.g.    tell application '7Edit'
  452. //            insertion point after word 5 of document 1
  453. //        end tell
  454.  
  455. OSErr    TextFormRelativePosition(TextToken* containerToken, AEDesc* selectionData,
  456.                                                     DescType wantClass, AEDesc* result)
  457. {
  458.     TextToken    aTextToken;
  459.     DescType     aPosition;
  460.     OSErr        err;
  461.     
  462.     aTextToken.tokenWindow = containerToken->tokenWindow;
  463.  
  464.     switch (wantClass)
  465.     {
  466.         case cInsertionPoint:
  467.             err = GetEnumeratedFromDescriptor(selectionData, &aPosition);
  468.             
  469.             switch (aPosition)
  470.             {
  471.                 case kAEPrevious:
  472.                 case kAEBefore:
  473.                 case kAEBeginning:
  474.                     // No change to offset - just 0 length now
  475.                     // containerToken.tokenOffset = containerToken.tokenOffset;
  476.                     aTextToken.tokenOffset = containerToken->tokenOffset;
  477.                     aTextToken.tokenLength = 0;
  478.                     break;
  479.             
  480.                 case kAENext:
  481.                 case kAEAfter:
  482.                 case kAEEnd:
  483.                     aTextToken.tokenOffset = containerToken->tokenOffset + containerToken->tokenLength;
  484.                     aTextToken.tokenLength = 0;
  485.                     break;
  486.                     
  487.                 default:
  488.                     err = errAEIllegalIndex;
  489.             }
  490.             break;
  491.             
  492.         default:
  493.             err = errAEWrongDataType;    // Could do cChar, cWord… but this is only a sample
  494.     }
  495.     
  496.     if (noErr != err) goto done;
  497.  
  498.     err = AECreateDesc(typeMyText, (Ptr)&aTextToken, sizeof(aTextToken), result);
  499.  
  500. done:
  501.     return(err);
  502. }
  503.  
  504.  
  505. // Tries to create a TextToken descriptor given a container which may
  506. // be a TextToken descriptor or a WindowToken descriptor. A
  507. // selectionData descriptor which can be of formAbsolutePosition,
  508. // formRange or formRelativePosition, and a wantClass which should
  509. // be cInsertionPoint, cChar, cText, cWord or cParagraph.
  510. //
  511. // e.g.    tell application '7Edit'
  512. //            first word of document 1 -- document 1 will go through WindowFromNullAccessor()
  513. //                                     -- which will return a WindowToken descriptor. This
  514. //                                     -- descriptor will then be coerced to a TextToken
  515. //                                     -- descriptor and used as the container.
  516. //        end tell
  517.  
  518. pascal OSErr    TextElemFromTextAccessor(DescType            wantClass,
  519.                                             AEDesc            *container,
  520.                                             DescType        containerClass,
  521.                                             DescType        form,
  522.                                             AEDesc            *selectionData,
  523.                                             AEDesc            *value,
  524.                                             long            theRefCon)
  525. {
  526. #pragma unused(containerClass)
  527.  
  528.     TextToken   containerToken;
  529.     long        index;
  530.     long        itemCount;
  531.     AEDesc        aDesc = {typeNull, NULL},
  532.                 resultDesc = {typeNull, NULL};
  533.     DescType    returnedType;
  534.     Size        actualSize;
  535.     OSErr       myErr;
  536.     
  537.                 // If it's a list then we need to call this accessor for every
  538.                 // item within the list (which could of course be more lists).
  539.     if (typeAEList == container->descriptorType)
  540.     {
  541.         myErr = AECreateList(NULL, 0 , false, value);    // Result will also be a list of items
  542.         if (noErr != myErr) goto done;
  543.         myErr = AECountItems(container, &itemCount);
  544.         if (noErr != myErr) goto done;
  545.  
  546.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  547.         {
  548.             myErr = AEGetNthDesc(container, index, typeWildCard, &returnedType, &aDesc);
  549.  
  550.             if (noErr == myErr)        // Call this function recursively if necessary
  551.                 myErr = TextElemFromTextAccessor(wantClass, &aDesc, returnedType,
  552.                                             form, selectionData, &resultDesc, theRefCon);
  553.             
  554.             if (noErr == myErr)        // Add item to the end of our list
  555.                 myErr = AEPutDesc(value, 0, &resultDesc);
  556.             
  557.             if (aDesc.dataHandle)
  558.                 AEDisposeDesc(&aDesc);
  559.             if (resultDesc.dataHandle)
  560.                 AEDisposeDesc(&resultDesc);
  561.         }
  562.     }
  563.     else
  564.     {                // We have a coercion handler from window to text
  565.         myErr = AECoerceDesc(container, typeMyText, &aDesc);
  566.         if (noErr != myErr) goto done;
  567.  
  568.                 // Get the containing TextToken
  569.         GetRawDataFromDescriptor(&aDesc, (Ptr)&containerToken, sizeof(containerToken), &actualSize);
  570.         
  571.         switch (form)
  572.         {
  573.             case formAbsolutePosition:
  574.                 myErr = TextFormAbsolutePosition(&containerToken, selectionData,
  575.                                                                     wantClass, value);
  576.                 break;                                        
  577.                 
  578.             case formRange:
  579.                 myErr = TextFormRange(&containerToken, selectionData,
  580.                                                             wantClass, value);
  581.                 break;
  582.                 
  583.             case formRelativePosition:
  584.                 myErr = TextFormRelativePosition(&containerToken, selectionData,
  585.                                                                 wantClass, value);
  586.                 break;
  587.                 
  588.             default:
  589.                 myErr = errAEBadKeyForm;
  590.         }
  591.     }
  592.  
  593. done:
  594.     if (aDesc.dataHandle)
  595.         AEDisposeDesc(&aDesc);
  596.         
  597.     return(myErr);
  598. }    // TextElemFromTextAccessor
  599.  
  600.  
  601. // Given a TextToken descriptor as a container convert this into 
  602. // a TextPropToken descriptor for the property.
  603.  
  604. pascal OSErr    PropertyFromTextAccessor(DescType            wantClass,
  605.                                             const AEDesc    *container,
  606.                                             DescType        containerClass,
  607.                                             DescType        form, 
  608.                                             const AEDesc    *selectionData,
  609.                                             AEDesc            *value,
  610.                                             long            theRefCon)
  611. {
  612. #pragma unused (theRefCon, containerClass)
  613.  
  614.     AEDesc            textDesc = {typeNull, NULL},
  615.                     propertyDesc = {typeNull, NULL};
  616.     Size            actualSize;
  617.     TextToken        aTextToken;
  618.     TextPropToken    aTextPropToken;
  619.     DescType        aProperty;
  620.     OSErr            err;
  621.     
  622.     if (cProperty != wantClass || formPropertyID != form)
  623.         return(errAEWrongDataType);
  624.         
  625.                 // Try and coerce to a TextToken descriptor
  626.     err = AECoerceDesc(container, typeMyText, &textDesc);
  627.     if (noErr != err) goto done;
  628.     
  629.                 // Get the TextToken
  630.     GetRawDataFromDescriptor(&textDesc, (Ptr)&aTextToken,
  631.                             sizeof(aTextToken), &actualSize);
  632.             
  633.                 // Make sure the selection data is typeType
  634.     err = AECoerceDesc(selectionData, typeType, &propertyDesc);
  635.     if (noErr != err) goto done;
  636.  
  637.                 // Get the property
  638.     GetRawDataFromDescriptor(&propertyDesc, (Ptr)&aProperty,
  639.                                     sizeof(aProperty),  &actualSize);
  640.             
  641.                 //    Combine the two into single token
  642.     aTextPropToken.tokenTextToken = aTextToken;
  643.     aTextPropToken.tokenProperty  = aProperty;
  644.     
  645.     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  646.                                 sizeof(aTextPropToken), value);
  647.  
  648. done:        
  649.     if (textDesc.dataHandle)
  650.         AEDisposeDesc(&textDesc);
  651.     if (propertyDesc.dataHandle)
  652.         AEDisposeDesc(&propertyDesc);
  653.         
  654.     return(err);
  655. } // PropertyFromTextAccessor
  656.  
  657.  
  658. // Given a WindowToken descriptor as a container convert this into 
  659. // a WindowPropToken descriptor for the property.
  660.  
  661. pascal OSErr    PropertyFromWndwAccessor(DescType            wantClass,
  662.                                             AEDesc            *container,
  663.                                             DescType        containerClass,
  664.                                             DescType        form, 
  665.                                             AEDesc            *selectionData,
  666.                                             AEDesc            *value,
  667.                                             long            theRefCon)
  668. {
  669. #pragma unused(containerClass)
  670.  
  671.     long                itemCount,
  672.                         index;
  673.     AEDesc                resultDesc = {typeNull, NULL},
  674.                         windowDesc = {typeNull, NULL},
  675.                         propDesc = {typeNull, NULL};
  676.     Size                actualSize;
  677.     DescType            returnedType;
  678.     WindowToken         theWindowToken;
  679.     WindowPropToken     myWindowProp;
  680.     OSErr               err;
  681.     
  682.     if (typeAEList == container->descriptorType)
  683.     {
  684.         err = AECreateList(NULL, 0 , false, value);        // Result will also be a list of items
  685.         if (noErr != err) goto done;
  686.         err = AECountItems(container, &itemCount);
  687.         if (noErr != err) goto done;
  688.     
  689.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  690.         {
  691.             err = AEGetNthDesc(container, index, typeWildCard, &returnedType, &windowDesc);
  692.     
  693.             if (noErr == err)                            // Recursively call this routine
  694.                                                         // - could be another list.
  695.                 err = PropertyFromWndwAccessor(wantClass, &windowDesc, windowDesc.descriptorType,
  696.                                                         form, selectionData, &resultDesc, theRefCon);
  697.             
  698.             if (noErr == err)                            // Add item to the end of our list
  699.                 err = AEPutDesc(value, 0, &resultDesc);
  700.             
  701.             if (windowDesc.dataHandle)
  702.                 AEDisposeDesc(&windowDesc);
  703.             if (resultDesc.dataHandle)
  704.                 AEDisposeDesc(&resultDesc);
  705.         }
  706.     }
  707.     else
  708.     {        // get the window token - it's the container
  709.         
  710.         err = AECoerceDesc(container, typeMyWndw, &windowDesc);
  711.         GetRawDataFromDescriptor(&windowDesc, (Ptr)&theWindowToken,
  712.                                         sizeof(theWindowToken), &actualSize);
  713.                                                             
  714.             // Check the window exists
  715.         
  716.         if (theWindowToken.tokenWindow == NULL)
  717.             err = errAEIllegalIndex;
  718.         else
  719.         {        // get the property - it's in the selection data
  720.             
  721.             err = AECoerceDesc(selectionData, typeType, &propDesc);
  722.             GetRawDataFromDescriptor(&propDesc, (Ptr)&returnedType,
  723.                                             sizeof(returnedType), &actualSize);
  724.             
  725.                 // Combine the two into single token
  726.  
  727.             myWindowProp.tokenWindowToken = theWindowToken;
  728.             myWindowProp.tokenProperty    = returnedType;
  729.             
  730.             err = AECreateDesc(typeMyWindowProp, (Ptr)&myWindowProp,
  731.                                                 sizeof(myWindowProp), value);
  732.         }
  733.     }
  734.     
  735. done:
  736.     if (windowDesc.dataHandle)
  737.         AEDisposeDesc(&windowDesc);
  738.     if (propDesc.dataHandle)
  739.         AEDisposeDesc(&propDesc);
  740.     if (resultDesc.dataHandle)
  741.         AEDisposeDesc(&resultDesc);
  742.         
  743.     return(err);
  744. } // PropertyFromWndwAccessor
  745.  
  746.  
  747. pascal OSErr    PropertyFromNullAccessor(DescType            wantClass,
  748.                                             AEDesc            *container,
  749.                                             DescType        containerClass,
  750.                                             DescType        form, 
  751.                                             AEDesc            *selectionData,
  752.                                             AEDesc            *value,
  753.                                             long            theRefCon)
  754. {
  755. #pragma unused (container, containerClass)
  756.  
  757.     AEDesc        aDesc = {typeNull, NULL};
  758.     OSErr        err;
  759.  
  760.     if ((wantClass != cProperty) || (form != formPropertyID))
  761.         return(errAEWrongDataType);
  762.  
  763.     switch (*(DescType *)*selectionData->dataHandle)
  764.     {
  765.         case pSelection:    // The selection defaults to the front window
  766.                             // selection.
  767.             err = GetDescOfNthWindow(1, &aDesc);    // Disposed of at end
  768.             if (noErr != err) goto done;
  769.             err = PropertyFromWndwAccessor(wantClass, &aDesc, typeMyWndw, form, 
  770.                                                     selectionData, value, theRefCon);
  771.             break;
  772.             
  773.         default:            // Otherwise try an application property - it is fron NULL
  774.             err = PropertyFromApplAccessor(wantClass, &aDesc, typeMyWndw, form, 
  775.                                                     selectionData, value, theRefCon);
  776.     }
  777.     
  778. done:
  779.     if (aDesc.dataHandle)
  780.         AEDisposeDesc(&aDesc);
  781.     
  782.     return(err);
  783. }
  784.  
  785.  
  786. // Convert a list of Token descriptors to a list of Property Token descriptors.
  787. // Only TextTokens and WindowTokens are supported in this version.
  788.  
  789. OSErr    TokenListToPropertyList(AEDesc* tokenList, DescType aProperty, AEDesc* result)
  790. {
  791.     AEDesc                aDesc = {typeNull, NULL},
  792.                         resultDesc = {typeNull, NULL};
  793.     DescType            returnedType;
  794.     long                itemCount,
  795.                         index;
  796.     WindowPropToken        aWindowPropToken;
  797.     TextPropToken        aTextPropToken;
  798.     Size                actualSize;
  799.     OSErr                err;
  800.  
  801.     err = AECreateList(NULL, 0 , false, result);        // Result will also be a list of items
  802.     if (noErr != err) goto done;
  803.     err = AECountItems(tokenList, &itemCount);        // Will return an error if not of type typeAEList
  804.     if (noErr != err) goto done;
  805.  
  806.     for (index = 1; index <= itemCount; index++)    // Do in forward order
  807.     {
  808.         err = AEGetNthDesc(tokenList, index, typeWildCard, &returnedType, &aDesc);
  809.  
  810.         if (noErr == err)                            // Create appropriate property token
  811.             switch (aDesc.descriptorType)
  812.             {
  813.                 case typeMyWndw:
  814.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aWindowPropToken,
  815.                                                     sizeof(WindowToken), &actualSize);
  816.                     aWindowPropToken.tokenProperty = aProperty;
  817.                     err = AECreateDesc(typeMyWindowProp, (Ptr)&aWindowPropToken,
  818.                                                     sizeof(aWindowPropToken), &resultDesc);
  819.                     break;
  820.                     
  821.                 case typeMyText:
  822.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aTextPropToken,
  823.                                                     sizeof(TextToken), &actualSize);
  824.                     aTextPropToken.tokenProperty = aProperty;
  825.                     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  826.                                                     sizeof(aTextPropToken), &resultDesc);
  827.                     break;
  828.                     
  829.                 case typeAEList:                    // Recursive call if a list
  830.                     err = TokenListToPropertyList(&aDesc, aProperty, &resultDesc);
  831.                     break;
  832.                     
  833.                 default:        // May already be a property token
  834.                     err = errAEBadListItem;
  835.             }
  836.         
  837.         if (noErr == err)        // Add item to the end of our list
  838.             err = AEPutDesc(result, 0, &resultDesc);
  839.         
  840.         if (aDesc.dataHandle)
  841.             AEDisposeDesc(&aDesc);
  842.         if (resultDesc.dataHandle)
  843.             AEDisposeDesc(&resultDesc);
  844.             
  845.         err = noErr;            // Try and do all the items we can in the list
  846.     }
  847.             
  848. done:
  849.     return(err);
  850. }
  851.  
  852.  
  853. // Given a container that is a list of Token descriptors, this routine
  854. // returns a list of PropToken descriptors.
  855.  
  856. pascal OSErr    PropertyFromListAccessor(DescType            wantClass,
  857.                                             AEDesc            *container,
  858.                                             DescType        containerClass,
  859.                                             DescType        form, 
  860.                                             AEDesc            *selectionData,
  861.                                             AEDesc            *value,
  862.                                             long            theRefCon)
  863. {
  864. #pragma unused(containerClass, theRefCon)
  865.  
  866.     OSErr        err;
  867.     
  868.     if (wantClass != cProperty && form != formPropertyID)
  869.         return(errAEBadKeyForm);
  870.     
  871.     err = TokenListToPropertyList(container, *(DescType *)*selectionData->dataHandle, value);
  872.  
  873.     return(err);
  874. }
  875.  
  876.  
  877. // Given a AppToken descriptor as a container convert this into 
  878. // a WindowPropToken descriptor for the property.
  879.  
  880. pascal OSErr    PropertyFromApplAccessor(DescType            wantClass,
  881.                                             const AEDesc    *container,
  882.                                             DescType        containerClass,
  883.                                             DescType        form, 
  884.                                             const AEDesc    *selectionData,
  885.                                             AEDesc            *value,
  886.                                             long            theRefCon)
  887. {
  888. #pragma unused (theRefCon, containerClass)
  889.  
  890.     OSErr         myErr;
  891.     OSErr         ignoreErr;
  892.     AppToken      theApplToken;
  893.     DescType      theProperty;
  894.     AEDesc        applDesc;
  895.     AEDesc        propDesc;
  896.     Size          actualSize;
  897.     ApplPropToken myApplProp;
  898.         
  899.     value->dataHandle     = nil;
  900.     applDesc.dataHandle   = nil;
  901.     propDesc.dataHandle   = nil;
  902.     
  903.     if ((wantClass != cProperty) ||
  904.           (form != formPropertyID))
  905.         {
  906.             return(errAEWrongDataType);
  907.         }
  908.     
  909.     /* get the application token - it's the container */
  910.     
  911.     myErr = AECoerceDesc(container, typeMyAppl, &applDesc);
  912.     GetRawDataFromDescriptor(&applDesc,
  913.                                                      (Ptr)&theApplToken,
  914.                                                      sizeof(theApplToken),
  915.                                                      &actualSize);
  916.             
  917.     /* get the property - it's in the selection data */
  918.     
  919.     myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  920.     GetRawDataFromDescriptor(&propDesc,
  921.                                                      (Ptr)&theProperty,
  922.                                                      sizeof(theProperty),
  923.                                                      &actualSize);
  924.     /*
  925.         Combine the two into single token
  926.     */
  927.     myApplProp.tokenApplToken    = theApplToken;
  928.     myApplProp.tokenApplProperty = theProperty;
  929.     
  930.     myErr = AECreateDesc(typeMyApplProp,
  931.                                              (Ptr)&myApplProp,
  932.                                              sizeof(myApplProp),
  933.                                              value);
  934.         
  935.     if (applDesc.dataHandle)
  936.         ignoreErr = AEDisposeDesc(&applDesc);
  937.         
  938.     if (propDesc.dataHandle)
  939.         ignoreErr = AEDisposeDesc(&propDesc);
  940.         
  941.     return(myErr);
  942. } // PropertyFromApplAccessor
  943.  
  944.  
  945. pascal OSErr    PropertyFromWinPropertyAccessor(DescType        wantClass,
  946.                                                 const AEDesc    *container,
  947.                                                 DescType        containerClass,
  948.                                                 DescType        form, 
  949.                                                 const AEDesc    *selectionData,
  950.                                                 AEDesc            *value,
  951.                                                 long            theRefCon)
  952. {
  953. #pragma unused(wantClass, containerClass, form, theRefCon)
  954.  
  955.     OSErr           myErr;
  956.     OSErr           ignoreErr;
  957.     WindowPropToken theWindowPropToken;
  958.     AEDesc          newDesc, propDesc;
  959.     Size            tokenSize;
  960.     DPtr            theDocument;
  961.     TextToken       theTextToken;
  962.     DescType        theProperty;
  963.     Size            actualSize;
  964.     TextPropToken   myTextProp;
  965.     
  966.  
  967.     /* the container is a window property token. Get the token for this */
  968.     /* and check that it is valid to get a property of this property */
  969.     
  970.     myErr = AECoerceDesc(container, typeMyWindowProp, &newDesc);
  971.     
  972.     if (myErr)
  973.      return(myErr);
  974.  
  975.     GetRawDataFromDescriptor(&newDesc,
  976.                                                      (Ptr)&theWindowPropToken,
  977.                                                      sizeof(theWindowPropToken),
  978.                                                      &tokenSize);
  979.                                                      
  980.   /* if the property is pSelection, we then want to convert this to a text token */
  981.     /* and then return a text property token */
  982.     
  983.     if (theWindowPropToken.tokenProperty == pSelection) 
  984.         {
  985.             theDocument = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
  986.             
  987.             /* build a text token to represent the selection */
  988.             theTextToken.tokenOffset = (**(theDocument->theText)).selStart + 1;
  989.             theTextToken.tokenLength = ((**(theDocument->theText)).selEnd -
  990.                                        (**(theDocument->theText)).selStart) -1;
  991.             theTextToken.tokenWindow = theWindowPropToken.tokenWindowToken.tokenWindow;
  992.             
  993.         
  994.             /* now get the property- it's in the selection data */
  995.             myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  996.             GetRawDataFromDescriptor(&propDesc,
  997.                                                              (Ptr)&theProperty,
  998.                                                              sizeof(theProperty),
  999.                                                              &actualSize);
  1000.             
  1001.             /* Combine the two into single token */
  1002.             myTextProp.tokenTextToken = theTextToken;
  1003.             myTextProp.tokenProperty  = theProperty;
  1004.     
  1005.               myErr = AECreateDesc(typeMyTextProp,(Ptr)&myTextProp,
  1006.                                              sizeof(myTextProp),value);
  1007.                                              
  1008.                                              
  1009.           if (propDesc.dataHandle) ignoreErr = AEDisposeDesc(&propDesc);
  1010.             if (newDesc.dataHandle)  ignoreErr = AEDisposeDesc(&newDesc);
  1011.  
  1012.           return myErr;
  1013.                                                                                                       
  1014.         }
  1015.     
  1016.     if (newDesc.dataHandle)  ignoreErr = AEDisposeDesc(&newDesc);
  1017.     
  1018.     return errAEWrongDataType;
  1019. }
  1020.